package org.movee.net.cfg.parser.antlr;

import org.movee.net.cfg.parser.parser.juniper.JuniperConfigContext;
import org.movee.net.cfg.parser.parser.juniper.JuniperConfigEntityType;
import org.movee.net.cfg.parser.parser.juniper.JuniperConfigModel;
import org.movee.net.cfg.parser.parser.juniper.JuniperConfigNode;
import org.movee.net.cfg.parser.parser.juniper.JuniperIntfIp6Parser;
import org.movee.net.cfg.parser.parser.juniper.JuniperIntfIpParser;
import org.movee.net.cfg.parser.parser.juniper.JuniperIntfParser;
import org.movee.net.cfg.parser.parser.juniper.JuniperSubIntfParser;
import org.movee.net.cfg.parser.parser.juniper.JuniperSystemParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

/**
 *
 *
 * @author 
 */
@Slf4j
public class JuniperCfgListenerImpl extends JuniperCfgBaseListener {

    private JuniperConfigNode currCfgNode = null;
    private final JuniperConfigContext context;
    private final JuniperSystemParser systemParser = new JuniperSystemParser();
    private final JuniperIntfParser intfParser = new JuniperIntfParser();
    private final JuniperSubIntfParser subIntfParser = new JuniperSubIntfParser();
    private final JuniperIntfIpParser intfIpParser = new JuniperIntfIpParser();
    private final JuniperIntfIp6Parser intfIp6Parser = new JuniperIntfIp6Parser();
    private final ObjectMapper jacksonMapper = new ObjectMapper();

    public JuniperCfgListenerImpl(String mgmtIp, String vendor) {
        this.context = new JuniperConfigContext(mgmtIp, vendor);
        this.currCfgNode = createRootConfigNode(context);
    }

    public JuniperConfigModel getModel() {
        return context.getModel();
    }

    @Override
    public void enterFile(JuniperCfgParser.FileContext ctx) {
        super.enterFile(ctx);
    }

    @Override
    public void exitFile(JuniperCfgParser.FileContext ctx) {
        super.exitFile(ctx);
    }

    @Override
    public void enterStatement(JuniperCfgParser.StatementContext ctx) {

        String originWord0 = ctx.word(0) == null ? "" : ctx.word(0).getText();

        String word0 = normKeyword(originWord0);
        String word1 = parseArgumentContent(ctx.word(1));

        JuniperConfigNode cfgNode = createConfigNode(currCfgNode, word0, word1);
        switch (cfgNode.getEntityType()) {
            case SYSTEM: {
                systemParser.parse(cfgNode);
                break;
            }
            case INTERFACE: {
                intfParser.parse(cfgNode);
                break;
            }
            case SUB_INTERFACE: {
                subIntfParser.parse(cfgNode);
                break;
            }
            case INTERFACE_IP: {
                intfIpParser.parse(cfgNode);
                break;
            }
            case INTERFACE_IP6: {
                intfIp6Parser.parse(cfgNode);
                break;
            }
            default: {

            }
        }

        currCfgNode = cfgNode;
        // log.info("==keyword text: {}", keywordText);
    }

    @Override
    public void exitStatement(JuniperCfgParser.StatementContext ctx) {
        if (currCfgNode.getIsEntityRoot()) {
            JuniperConfigContext context = currCfgNode.getContext();
            JuniperConfigModel model = context.getModel();
            JuniperConfigEntityType type = currCfgNode.getEntityType();
            Object entityInstance = context.remParsingEntity(type);
            switch (type) {
                case INTERFACE:
                case SUB_INTERFACE: {
                    JuniperConfigModel.Interface intf = (JuniperConfigModel.Interface) entityInstance;
                    model.putIntf(intf.getName(), intf);
                    break;
                }
                case INTERFACE_IP: {
                    JuniperConfigModel.Interface subIntf = (JuniperConfigModel.Interface) context.getParsingEntity(JuniperConfigEntityType.SUB_INTERFACE);
                    subIntf.getIps().add((JuniperConfigModel.InterfaceIp) entityInstance);
                    break;
                }
                case INTERFACE_IP6: {
                    JuniperConfigModel.Interface subIntf = (JuniperConfigModel.Interface) context.getParsingEntity(JuniperConfigEntityType.SUB_INTERFACE);
                    subIntf.getIp6s().add((JuniperConfigModel.InterfaceIp6) entityInstance);
                    break;
                }
            }
        }

        currCfgNode = currCfgNode.getParent();
    }

    private String getQuotedStringContent(String quotedStr) {
        if (StringUtils.hasLength(quotedStr) && quotedStr.length() >= 2) {
            return quotedStr.substring(1, quotedStr.length() - 1);
        }
        return "";
    }

    private String parseArgumentContent(JuniperCfgParser.WordContext ctx) {
        String content = "";
        if (ctx != null) {
            if (ctx.SQUOTE_STRING() != null) {
                String quotedStr = ctx.SQUOTE_STRING().getText();
                content = getQuotedStringContent(quotedStr);
            } else if (ctx.DQUOTE_STRING() != null) {
                String quotedStr = ctx.DQUOTE_STRING().getText();
                content = getQuotedStringContent(quotedStr);
            } else if (ctx.WORD() != null) {
                content = ctx.WORD().getText();
            }

        }

        return content;
    }

    private String normKeyword(String origin) {
        if (StringUtils.hasLength(origin) && origin.charAt(origin.length() - 1) == ':') {
            return origin.substring(0, origin.length() - 1);
        }

        return origin;
    }

    private JuniperConfigNode createConfigNode(JuniperConfigNode parent, String word0, String word1) {
        JuniperConfigNode cfgNode = new JuniperConfigNode();
        cfgNode.setParent(parent);
        cfgNode.setWord0(word0);
        cfgNode.setWord1(word1);
        cfgNode.setIsRoot(false);
        cfgNode.setContext(parent.getContext());

        if ("system".equals(word0) && parent.getIsRoot()) {
            cfgNode.setIsEntityRoot(true);
            cfgNode.setEntityType(JuniperConfigEntityType.SYSTEM);
        } else if ("interfaces".equals(word0) && parent.getIsRoot()) {
            cfgNode.setIsEntityRoot(true);
            cfgNode.setEntityType(JuniperConfigEntityType.INTERFACES);
        } else if (parent.getIsEntityRoot() && parent.getEntityType() == JuniperConfigEntityType.INTERFACES) {
            cfgNode.setIsEntityRoot(true);
            cfgNode.setEntityType(JuniperConfigEntityType.INTERFACE);
        } else if ("unit".equals(word0)
                && parent.getIsEntityRoot()
                && parent.getEntityType() == JuniperConfigEntityType.INTERFACE) {
            cfgNode.setIsEntityRoot(true);
            cfgNode.setEntityType(JuniperConfigEntityType.SUB_INTERFACE);
        } else if ("address".equals(word0)
                && "family".equals(parent.getWord0())
                && "inet".equals(parent.getWord1())
                && parent.getParent() != null
                && parent.getParent().getIsEntityRoot()
                && parent.getParent().getEntityType() == JuniperConfigEntityType.SUB_INTERFACE) {
            cfgNode.setIsEntityRoot(true);
            cfgNode.setEntityType(JuniperConfigEntityType.INTERFACE_IP);
        } else if ("address".equals(word0)
                && "family".equals(parent.getWord0())
                && "inet6".equals(parent.getWord1())
                && parent.getParent() != null
                && parent.getParent().getIsEntityRoot()
                && parent.getParent().getEntityType() == JuniperConfigEntityType.SUB_INTERFACE) {
            cfgNode.setIsEntityRoot(true);
            cfgNode.setEntityType(JuniperConfigEntityType.INTERFACE_IP6);
        } else if (parent.getIsRoot()) {
            // 暂不支持解析的一级节点
            cfgNode.setIsEntityRoot(true);
            cfgNode.setEntityType(JuniperConfigEntityType.UNKNOWN);
        } else {
            // 支持解析或不支持解析的非根节点
            cfgNode.setIsEntityRoot(false);
            // 继承父节点的
            cfgNode.setEntityType(parent.getEntityType());
        }

        return cfgNode;
    }

    private JuniperConfigNode createRootConfigNode(JuniperConfigContext context) {
        JuniperConfigNode cfgNode = new JuniperConfigNode();
        cfgNode.setParent(null);
        cfgNode.setWord0("root");
        cfgNode.setWord1("root");
        cfgNode.setIsRoot(true);
        cfgNode.setIsEntityRoot(false);
        cfgNode.setEntityType(JuniperConfigEntityType.ROOT);
        cfgNode.setContext(context);
        return cfgNode;
    }




}
